﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Nova.Parsing.GoldParser.Semantic;
using Nova.Parsing.Tokens;

namespace Nova.Parsing.Constructs
{
    public abstract class StatementConstruct : NovaConstruct
    {
    }

    public sealed class StatementSet : StatementConstruct, IEnumerable<StatementConstruct>
    {
        private StatementConstruct m_CurrentStatement;
        private StatementSet m_NextStatementSet;

        [Rule(@"<Statements> ::= <Statement> <Statements>")]
        [Rule(@"<Statements> ::= <Statement>")]
        public StatementSet(StatementConstruct statement, StatementSet nextStatmentSet)
        {
            m_CurrentStatement = statement;
            m_NextStatementSet = nextStatmentSet;
        }

        public StatementSet(StatementConstruct statement)
        {
            m_CurrentStatement = statement;
            m_NextStatementSet = null;
        }

        public StatementConstruct CurrentStatement
        {
            get { return m_CurrentStatement; }
        }

        public StatementSet NextStatementSet
        {
            get { return m_NextStatementSet; }
        }

        public IEnumerator<StatementConstruct> GetEnumerator()
        {
            for (StatementSet set = this; set != null; set = set.NextStatementSet)
            {
                if (set.CurrentStatement != null)
                {
                    yield return set.CurrentStatement;
                }
            }
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }

    public sealed class ConditionalStatement : StatementConstruct
    {
        private ExpressionConstruct m_Condition;
        private StatementConstruct m_ThenStatement;
        private StatementConstruct m_Statement;

        [Rule(@"<Statement> ::= if '(' <Expression> ')' <Statement>")]
        [Rule(@"<Statement> ::= if '(' <Expression> ')' <Then Statement> else <Statement>")]
        [Rule(@"<Then Statement> ::= if '(' <Expression> ')' <Then Statement> else <Then Statement>")]
        public ConditionalStatement(IgnoredToken iA, IgnoredToken iB, ExpressionConstruct expression,
            IgnoredToken iC, StatementConstruct statement, IgnoredToken iD, StatementConstruct statementB)
        {
            m_Condition = expression;

            if (statementB == null)
            {
                m_Statement = statement;
                m_ThenStatement = null;
            }
            else
            {
                m_ThenStatement = statement;
                m_Statement = statementB;
            }
        }

        public ExpressionConstruct Condition
        {
            get { return m_Condition; }
        }

        public StatementConstruct ThenStatement
        {
            get { return m_ThenStatement; }
        }

        public StatementConstruct Statement
        {
            get { return m_Statement; }
        }
    }

    public sealed class LoopStatement : StatementConstruct
    {
        // Common Loop properties
        private LoopStatementType m_LoopType;
        private ExpressionConstruct m_Condition;
        private StatementConstruct m_Statement;

        // For Loop Statements
        private StatementConstruct m_InitStatement;
        private StatementConstruct m_IterationStatement;

        #region Rule Constructors

        [Rule(@"<Statement> ::= for '(' <For-Loop Exp Init> ';' <For-Loop Exp Cond> ';' <For-Loop Exp Iter> ')' <Statement>")]
        [Rule(@"<Then Statement> ::= for '(' <For-Loop Exp Init> ';' <For-Loop Exp Cond> ';' <For-Loop Exp Iter> ')' <Then Statement>")]
        public LoopStatement(IgnoredToken iA, IgnoredToken iB, StatementConstruct initStatement,
                             IgnoredToken iC, ExpressionConstruct condition, IgnoredToken iD,
                             StatementConstruct iterStatement, IgnoredToken iE, StatementConstruct statement)
        {
            m_LoopType = LoopStatementType.For;
            m_Condition = condition;
            m_InitStatement = initStatement;
            m_IterationStatement = iterStatement;
            m_Statement = statement;
        }

        [Rule(@"<Statement> ::= while '(' <Expression> ')' <Statement> ")]
        [Rule(@"<Then Statement> ::= while '(' <Expression> ')' <Then Statement>")]
        public LoopStatement(IgnoredToken iA, IgnoredToken iB, ExpressionConstruct expression, IgnoredToken iC,
                             StatementConstruct statement)
        {
            m_LoopType = LoopStatementType.While;
            m_Condition = expression;
            m_Statement = statement;
            m_IterationStatement = null;
            m_InitStatement = null;
        }

        [Rule(@"<Normal Statement> ::= do <Normal Statement> while '(' <Expression> ')' ';'")]
        public LoopStatement(IgnoredToken iA, StatementConstruct statement, IgnoredToken iB,
                             IgnoredToken iC, ExpressionConstruct expression, IgnoredToken iD, IgnoredToken iE)
        {
            m_LoopType = LoopStatementType.DoWhile;
            m_Condition = expression;
            m_Statement = statement;
            m_IterationStatement = null;
            m_InitStatement = null;
        }

        #endregion

        public LoopStatementType LoopType
        {
            get { return m_LoopType; }
        }

        public ExpressionConstruct Condition
        {
            get { return m_Condition; }
        }

        public StatementConstruct Statement
        {
            get { return m_Statement; }
        }

        public StatementConstruct InitStatement
        {
            get { return m_InitStatement; }
        }

        public StatementConstruct InterationStatement
        {
            get { return m_IterationStatement; }
        }

    }

    public sealed class KeywordStatement : StatementConstruct
    {
        private NovaKeyword m_Keyword;

        [Rule(@"<Normal Statement> ::= break ';'")]
        [Rule(@"<Normal Statement> ::= continue ';'")]
        [Rule(@"<Normal Statement> ::= return ';'")]
        public KeywordStatement(KeywordToken keyword, IgnoredToken iA)
        {
            m_Keyword = keyword.Keyword;
        }

        public NovaKeyword Keyword
        {
            get { return m_Keyword; }
        }
    }

    public sealed class SwitchStatement : StatementConstruct
    {
        private ExpressionConstruct m_SwitchExpression;
        private CaseBlockSetConstruction m_CaseBlocks;

        [Rule(@"<Normal Statement> ::= switch '(' <Expression> ')' '{' <Case-Blocks> '}'")]
        public SwitchStatement(IgnoredToken iA, IgnoredToken iB, ExpressionConstruct expression,
                               IgnoredToken iC, IgnoredToken iD, CaseBlockSetConstruction caseBlocks,
                               IgnoredToken iE)
        {
            m_SwitchExpression = expression;
            m_CaseBlocks = caseBlocks;
        }

        public ExpressionConstruct SwitchExpression
        {
            get { return m_SwitchExpression; }
        }

        public CaseBlockSetConstruction CaseStatements
        {
            get { return m_CaseBlocks; }
        }
    }

    public sealed class StatementBlock : StatementConstruct
    {
        private StatementSet m_Statements;

        [Rule(@"<Normal Statement> ::= <Statement Block>")]
        public StatementBlock(StatementBlock statementBlock)
        {
            m_Statements = statementBlock.Statements;
        }

        [Rule(@"<Statement Block> ::= '{' <Statements> '}' ")]
        public StatementBlock(IgnoredToken iA, StatementSet statements, IgnoredToken iB)
        {
            m_Statements = statements;
        }

        [Rule(@"<Statement Block> ::= '{' '}'")]
        public StatementBlock(IgnoredToken iA, IgnoredToken iB)
        {
            m_Statements = null;
        }

        public StatementSet Statements
        {
            get { return m_Statements; }
        }
    }

    public sealed class VarDeclarationStatement : StatementConstruct
    {
        private string m_VarName;
        private ExpressionConstruct m_VarInitExpression;

        [Rule(@"<Normal Statement> ::= <Var Declaration> ';'")]
        public VarDeclarationStatement(VarDeclarationStatement statement, IgnoredToken iA)
        {
            this.m_VarInitExpression = statement.VariableAssignExpression;
            this.m_VarName = statement.VariableName;
        }

        [Rule(@"<Var Declaration> ::= var Identifier '=' <Expression>")]
        [Rule(@"<Var Declaration> ::= var Identifier")]
        public VarDeclarationStatement(IgnoredToken iA, Identifier varName, OperatorToken iB, ExpressionConstruct expression)
        {
            m_VarName = (string)varName.Value;
            m_VarInitExpression = expression;
        }

        public string VariableName
        {
            get { return m_VarName; }
        }

        public ExpressionConstruct VariableAssignExpression
        {
            get { return m_VarInitExpression; }
        }

        public override string ToString()
        {
            if (m_VarInitExpression == null)
            {
                return "var " + m_VarName;
            }
            else
            {
                return String.Format("var {0} = {1}", m_VarName, m_VarInitExpression.ToString());
            }
        }
    }

    public sealed class VarStatement : StatementConstruct
    {
        private VariableConstruct m_Variable;
        private OperatorType m_OpType;
        private ExpressionConstruct m_Expression;

        [Rule(@"<Normal Statement> ::= <Var Statement> ';'")]
        public VarStatement(VarStatement varStatement, IgnoredToken iA)
        {
            this.m_Variable = varStatement.Variable;
            this.m_OpType = varStatement.Operator;
            this.m_Expression = varStatement.AssignmentExpression;
        }

        [Rule(@"<Var Statement> ::= <Variable Iden> '=' <Expression>")]
        [Rule(@"<Var Statement> ::= <Variable Iden> '>>=' <Expression>")]
        [Rule(@"<Var Statement> ::= <Variable Iden> '<<=' <Expression>")]
        [Rule(@"<Var Statement> ::= <Variable Iden> '>>>=' <Expression>")]
        [Rule(@"<Var Statement> ::= <Variable Iden> '<<<=' <Expression>")]
        [Rule(@"<Var Statement> ::= <Variable Iden> '^=' <Expression>")]
        [Rule(@"<Var Statement> ::= <Variable Iden> '|=' <Expression>")]
        [Rule(@"<Var Statement> ::= <Variable Iden> '&=' <Expression>")]
        [Rule(@"<Var Statement> ::= <Variable Iden> '-=' <Expression>")]
        [Rule(@"<Var Statement> ::= <Variable Iden> '*=' <Expression>")]
        [Rule(@"<Var Statement> ::= <Variable Iden> '/=' <Expression>")]
        [Rule(@"<Var Statement> ::= <Variable Iden> '+=' <Expression>")]
        [Rule(@"<Var Statement> ::= <Variable Iden> '++'")]
        [Rule(@"<Var Statement> ::= <Variable Iden> '--'")]
        public VarStatement(VariableConstruct var, OperatorToken op, ExpressionConstruct expression)
        {
            m_Variable = var;
            m_OpType = op.Operator;
            m_Expression = expression;
        }

        public VariableConstruct Variable
        {
            get { return m_Variable; }
        }

        public OperatorType Operator
        {
            get { return m_OpType; }
        }

        public ExpressionConstruct AssignmentExpression
        {
            get { return m_Expression; }
        }
    }

    public sealed class NullStatement : StatementConstruct
    {
        [Rule(@"<For-Loop Exp Init> ::= ")]
        [Rule(@"<For-Loop Exp Iter> ::= ")]
        public NullStatement()
        {
        }

        [Rule(@"<Normal Statement> ::= ';'")]
        public NullStatement(IgnoredToken iA)
        {
        }
    }

    public sealed class LogStatement : StatementConstruct
    {
        private NovaLogLevel m_LogLevel;
        private string m_LogMessage;

        [Rule(@"<Normal Statement> ::= log notice StringLiteral ';'")]
        [Rule(@"<Normal Statement> ::= log warn StringLiteral ';'")]
        [Rule(@"<Normal Statement> ::= log info StringLiteral ';'")]
        [Rule(@"<Normal Statement> ::= log error StringLiteral ';'")]
        public LogStatement(IgnoredToken iA, LogLevelToken logLevel, StringLiteral message, IgnoredToken iB)
        {
            m_LogLevel = logLevel.LogLevel;
            m_LogMessage = message.Value.ToString();
        }

        public NovaLogLevel LogLevel
        {
            get { return m_LogLevel; }
        }

        public string LogMessage
        {
            get { return m_LogMessage; }
        }
    }

    public sealed class ThrowStatement : StatementConstruct
    {
        private string m_ExceptionName;

        [Rule(@"<Normal Statement> ::= throw Identifier ';'")]
        public ThrowStatement(IgnoredToken iA, Identifier name, IgnoredToken iB)
        {
            m_ExceptionName = name.Value.ToString();
        }

        public string ExceptionName
        {
            get { return m_ExceptionName; }
        }
    }

    public sealed class FunctionStatement : StatementConstruct
    {
        private string m_FunctionName;
        private ArgumentSetConstruction m_Arguments;

        [Rule(@"<Normal Statement> ::= Identifier '(' <Argument List Opt> ')' ';'")]
        public FunctionStatement(Identifier name, IgnoredToken iA, ArgumentSetConstruction argSet, IgnoredToken iB, IgnoredToken iC)
        {
            m_FunctionName = name.Value.ToString();
            m_Arguments = argSet;
        }

        public string FunctionName
        {
            get { return m_FunctionName; }
        }
        
        public ArgumentSetConstruction Arguments
        {
            get { return m_Arguments; }
        }
    }
}
